import json

from flask import flash, g
from flask_appbuilder import CompactCRUDMixin
from flask_appbuilder.fieldwidgets import Select2Widget
from flask_appbuilder.models.sqla.interface import SQLAInterface
from flask_babel import lazy_gettext as _
from wtforms import SelectField, StringField
from wtforms.ext.sqlalchemy.fields import QuerySelectField
from wtforms.validators import DataRequired

# Import application builder, database instance, and security manager
# 导入应用构建器、数据库实例和安全管理器
from myapp.app import appbuilder, db, security_manager
# Import custom form widgets
# 导入自定义表单组件
from myapp.forms import MyBS3TextAreaFieldWidget, MyBS3TextFieldWidget
# Import Project and Project_User models
# 导入Project和Project_User模型
from myapp.models.model_team import Project, Project_User
# Import core utilities
# 导入核心工具
from myapp.utils import core

# Import base view classes for custom filter, model view, and user roles retrieval
# 导入基础视图类，用于自定义过滤器、模型视图和用户角色检索
from .base import (
    MyappFilter,
    MyappModelView,
    get_user_roles,
)
# Import base API class
# 导入基础API类
from .baseApi import MyappModelRestApi


# Base class for Project_User_ModelView, used in table show interface
# Project_User_ModelView的基类，用于表格显示界面
class Project_User_ModelView_Base:
    # Title for the view
    # 视图的标题
    label_title = '组成员'
    # Data model interface for Project_User
    # Project_User的数据模型接口
    datamodel = SQLAInterface(Project_User)
    # Columns to display in the add form
    # 添加表单中显示的列
    add_columns = ['project', 'user', 'role']
    # Columns to display in the edit form (same as add_columns)
    # 编辑表单中显示的列（与add_columns相同）
    edit_columns = add_columns
    # Columns to display in the list view
    # 列表视图中显示的列
    list_columns = ['user', 'role']

    # Extra fields for the add form
    # 添加表单的额外字段
    add_form_extra_fields = {
        'project': QuerySelectField(
            '项目组',
            query_factory=lambda: db.session.query(Project),
            allow_blank=True,
            widget=Select2Widget(extra_classes='readonly'),
            description='只有creator可以添加修改组成员，可以添加多个creator',
        ),
        'role': SelectField(
            '成员角色',
            widget=Select2Widget(),
            default='dev',
            choices=[[x, x] for x in ['dev', 'ops', 'creator']],
            description='只有creator可以添加修改组成员，可以添加多个creator',
            validators=[DataRequired()],
        ),
    }
    # Extra fields for the edit form (same as add_form_extra_fields)
    # 编辑表单的额外字段（与add_form_extra_fields相同）
    edit_form_extra_fields = add_form_extra_fields

    # Pre-add hook: called before adding a new item
    # 预添加钩子：在添加新项目之前调用
    # @pysnooper.snoop()
    def pre_add(self, item):
        # Get user roles
        # 获取用户角色
        user_roles = [role.name.lower() for role in list(get_user_roles())]
        # If user is not admin and not a creator of the project, raise an exception
        # 如果用户不是管理员且不是项目的创建者，则抛出异常
        if 'admin' in user_roles:
            return
        if g.user.username not in item.project.get_creators():
            raise Exception('just creator can add/edit user')

    # Pre-update hook: called before updating an existing item
    # 预更新钩子：在更新现有项目之前调用
    def pre_update(self, item):
        # Get user roles
        # 获取用户角色
        user_roles = [role.name.lower() for role in list(get_user_roles())]
        # If user is not admin and not a creator of the project, raise an exception
        # 如果用户不是管理员且不是项目的创建者，则抛出异常
        if 'admin' in user_roles:
            return
        if g.user.username not in item.project.get_creators():
            raise Exception('just creator can add/edit user')


# Project_User_ModelView class, inheriting from base, CompactCRUDMixin, and MyappModelView
# Project_User_ModelView类，继承自基类、CompactCRUDMixin和MyappModelView
class Project_User_ModelView(Project_User_ModelView_Base, CompactCRUDMixin, MyappModelView):
    # Data model interface for Project_User
    # Project_User的数据模型接口
    datamodel = SQLAInterface(Project_User)


# Add the Project_User_ModelView to the appbuilder without a menu entry
# 将Project_User_ModelView添加到appbuilder，不带菜单项
appbuilder.add_view_no_menu(Project_User_ModelView)


# Project_User_ModelView_Api class, inheriting from base and MyappModelRestApi
# Project_User_ModelView_Api类，继承自基类和MyappModelRestApi
class Project_User_ModelView_Api(Project_User_ModelView_Base, MyappModelRestApi):
    # Data model interface for Project_User
    # Project_User的数据模型接口
    datamodel = SQLAInterface(Project_User)
    # Route base for the API endpoint
    # API端点的路由基础
    route_base = '/project_user_modelview/api'
    # Columns to display in the add form (commented out, using base class definition)
    # 添加表单中显示的列（已注释，使用基类定义）
    # add_columns = ['user', 'role']
    # Columns to display in the add form
    # 添加表单中显示的列
    add_columns = ['project', 'user', 'role']
    # Columns to display in the edit form (same as add_columns)
    # 编辑表单中显示的列（与add_columns相同）
    edit_columns = add_columns


# Add the Project_User_ModelView_Api to the appbuilder
# 将Project_User_ModelView_Api添加到appbuilder
appbuilder.add_api(Project_User_ModelView_Api)


# Custom filter for Project, to get a specific type of project group
# Project的自定义过滤器，用于获取特定类型的项目组
class Project_Filter(MyappFilter):
    # Apply the filter to the query
    # 将过滤器应用于查询
    # @pysnooper.snoop()
    def apply(self, query, value):
        # Commented out: user role check for admin
        # 已注释：管理员的用户角色检查
        # user_roles = [role.name.lower() for role in list(get_user_roles())]
        # if "admin" in user_roles:
        #     return query.filter(Project.type == value).order_by(Project.id.desc())
        # Filter by project type and order by ID in descending order
        # 按项目类型过滤并按ID降序排序
        return query.filter(self.model.type == value).order_by(self.model.id.desc())


# Custom filter for Project, to get project groups the user has joined
# Project的自定义过滤器，用于获取用户已加入的项目组
class Project_Join_Filter(MyappFilter):
    # Apply the filter to the query
    # 将过滤器应用于查询
    # @pysnooper.snoop()
    def apply(self, query, value):
        # If user is admin, return all projects of the specified type
        # 如果用户是管理员，则返回指定类型的所有项目
        if g.user.is_admin:
            return query.filter(self.model.type == value).order_by(self.model.id.desc())
        # Get IDs of projects the user has joined
        # 获取用户已加入的项目的ID
        join_projects_id = security_manager.get_join_projects_id(db.session)
        # Filter by joined project IDs and project type, then order by ID in descending order
        # 按已加入的项目ID和项目类型过滤，然后按ID降序排序
        return (
            query.filter(self.model.id.in_(join_projects_id))
            .filter(self.model.type == value)
            .order_by(self.model.id.desc())
        )


# Function to query joined organization projects
# 查询已加入的组织项目的功能
def filter_join_org_project():
    # Build base query for Project
    # 构建Project的基础查询
    query = db.session.query(Project)
    # Commented out: user role check for admin
    # 已注释：管理员的用户角色检查
    # user_roles = [role.name.lower() for role in list(get_user_roles())]
    # if "admin" in user_roles:
    # If user is admin, return all organization projects
    # 如果用户是管理员，则返回所有组织项目
    if g.user.is_admin:
        return query.filter(Project.type == 'org').order_by(Project.id.desc())

    # Get current user's ID
    # 获取当前用户ID
    my_user_id = g.user.get_id() if g.user else 0
    # Query project IDs where the user is a member
    # 查询用户是成员的项目ID
    owner_ids_query = db.session.query(Project_User.project_id).filter(
        Project_User.user_id == my_user_id
    )

    # Filter by owned project IDs and project type 'org', then order by ID in descending order
    # 按拥有的项目ID和项目类型'org'过滤，然后按ID降序排序
    return (
        query.filter(Project.id.in_(owner_ids_query))
        .filter(Project.type == 'org')
        .order_by(Project.id.desc())
    )


# Base class for Project_ModelView
# Project_ModelView的基类
class Project_ModelView_Base:
    # Title for the view
    # 视图的标题
    label_title = '项目组'
    # Data model interface for Project
    # Project的数据模型接口
    datamodel = SQLAInterface(Project)
    # Base permissions for the view
    # 视图的基本权限
    base_permissions = ['can_add', 'can_edit', 'can_delete', 'can_list', 'can_show']
    # Default order for listing items
    # 列表项的默认排序
    base_order = ('id', 'desc')
    # Columns to display in the list view
    # 列表视图中显示的列
    list_columns = ['name', 'user', 'type']
    # Column widths for display
    # 显示的列宽
    cols_width = {
        'name': {'type': 'ellip2', 'width': 200},
        'user': {'type': 'ellip3', 'width': 700},
        'type': {'type': 'ellip2', 'width': 200},
    }
    # Related views to display
    # 要显示的相关视图
    related_views = [
        Project_User_ModelView,
    ]
    # Columns to display in the add form
    # 添加表单中显示的列
    add_columns = ['name', 'describe', 'expand']
    # Columns to display in the edit form (same as add_columns)
    # 编辑表单中显示的列（与add_columns相同）
    edit_columns = add_columns

    # Pre-add-get hook: called before displaying the add form
    # 预添加获取钩子：在显示添加表单之前调用
    # @pysnooper.snoop()
    def pre_add_get(self):
        # Set 'type' field for edit form extra fields
        # 为编辑表单额外字段设置'type'字段
        self.edit_form_extra_fields['type'] = StringField(
            _(self.datamodel.obj.lab('type')),
            description='项目分组',
            widget=MyBS3TextFieldWidget(value=self.project_type, readonly=1),
            default=self.project_type,
        )
        # Set add form extra fields to be the same as edit form extra fields
        # 将添加表单额外字段设置为与编辑表单额外字段相同
        self.add_form_extra_fields = self.edit_form_extra_fields

    # Pre-update hook: called before updating an existing item
    # 预更新钩子：在更新现有项目之前调用
    def pre_update(self, item):
        # If item type is not set, use project_type
        # 如果未设置项目类型，则使用project_type
        if not item.type:
            item.type = self.project_type
        # Validate and format expand JSON field
        # 验证并格式化expand JSON字段
        if item.expand:
            core.validate_json(item.expand)
            item.expand = json.dumps(json.loads(item.expand), indent=4, ensure_ascii=False)
        # Check user permissions
        # 检查用户权限
        user_roles = [role.name.lower() for role in list(get_user_roles())]
        if 'admin' in user_roles:
            return
        if g.user.username not in item.get_creators():
            raise Exception('just creator can add/edit')

    # Pre-update-get hook: called before displaying the edit form, checks permissions
    # 预更新获取钩子：在显示编辑表单之前调用，检查权限
    def pre_update_get(self, item):
        self.pre_add_get()
        self.check_item_permissions(item)
        if not self.user_permissions['edit']:
            flash('just creator can add/edit user', 'warning')
            raise Exception('just creator can add/edit user')

    # Check item-level permissions
    # 检查项目级权限
    def check_item_permissions(self, item):
        # If user is admin or a creator of the project, grant all permissions
        # 如果用户是管理员或项目的创建者，则授予所有权限
        if g.user.is_admin or g.user.username in item.get_creators():
            self.user_permissions = {'add': True, 'edit': True, 'delete': True, 'show': True}
        else:
            # Otherwise, grant only add and show permissions
            # 否则，仅授予添加和显示权限
            self.user_permissions = {'add': True, 'edit': False, 'delete': False, 'show': True}

    # Post-add hook: called after adding a new item, adds the creator as a project user
    # 后添加钩子：在添加新项目后调用，将创建者添加为项目用户
    def post_add(self, item):
        # If item type is not set, use project_type
        # 如果未设置项目类型，则使用project_type
        if not item.type:
            item.type = self.project_type
        # Create a Project_User entry for the creator
        # 为创建者创建Project_User条目
        creator = Project_User(role='creator', user=g.user, project=item)
        db.session.add(creator)
        db.session.commit()

    # Post-list hook: called after fetching list data, sorts items by expand index
    # 后列表钩子：在获取列表数据后调用，按expand索引排序项目
    # @pysnooper.snoop()
    def post_list(self, items):
        return core.sort_expand_index(items, db.session)


# Commented out: Project_ModelView for job templates
# 已注释：用于作业模板的Project_ModelView
# class Project_ModelView_job_template(Project_ModelView_Base,MyappModelView):
#     project_type = 'job-template'
#     base_filters = [["id", Project_Filter, project_type]]
#     datamodel = SQLAInterface(Project)
#     label_title = '模板分类'
#


# Project_ModelView_job_template_Api class, inheriting from base and MyappModelRestApi
# Project_ModelView_job_template_Api类，继承自基类和MyappModelRestApi
class Project_ModelView_job_template_Api(Project_ModelView_Base, MyappModelRestApi):
    # Route base for the API endpoint
    # API端点的路由基础
    route_base = '/project_modelview/job_template/api'
    # Data model interface for Project
    # Project的数据模型接口
    datamodel = SQLAInterface(Project)
    # Project type for this view
    # 此视图的项目类型
    project_type = 'job-template'
    # Base filters for this view
    # 此视图的基本过滤器
    base_filters = [['id', Project_Filter, project_type]]
    # Related views to display
    # 要显示的相关视图
    related_views = [
        Project_User_ModelView_Api,
    ]
    # Title for the view
    # 视图的标题
    label_title = '模板分类'
    # Extra fields for the edit form
    # 编辑表单的额外字段
    edit_form_extra_fields = {
        'type': StringField(
            _(datamodel.obj.lab('type')),
            description='模板分类',
            widget=MyBS3TextFieldWidget(value=project_type, readonly=1),
            default=project_type,
        ),
        'expand': StringField(
            _(datamodel.obj.lab('expand')),
            description='扩展参数。示例参数：<br>"index": 0表示在pipeline编排中模板列表的排序位置',
            widget=MyBS3TextAreaFieldWidget(),
            default='{}',
        ),
    }
    # Extra fields for the add form (same as edit_form_extra_fields)
    # 添加表单的额外字段（与edit_form_extra_fields相同）
    add_form_extra_fields = edit_form_extra_fields


# Add the Project_ModelView_job_template_Api to the appbuilder
# 将Project_ModelView_job_template_Api添加到appbuilder
appbuilder.add_api(Project_ModelView_job_template_Api)


# Commented out: Project_ModelView for organizations
# 已注释：用于组织的Project_ModelView
# class Project_ModelView_org(Project_ModelView_Base,MyappModelView):
#     project_type='org'
#     base_filters = [["id", Project_Filter, project_type]]
#     datamodel = SQLAInterface(Project)
#     label_title = '项目分组'
#
#


# Project_ModelView_org_Api class, inheriting from base and MyappModelRestApi
# Project_ModelView_org_Api类，继承自基类和MyappModelRestApi
class Project_ModelView_org_Api(Project_ModelView_Base, MyappModelRestApi):
    # Route base for the API endpoint
    # API端点的路由基础
    route_base = '/project_modelview/org/api'
    # Data model interface for Project
    # Project的数据模型接口
    datamodel = SQLAInterface(Project)
    # Project type for this view
    # 此视图的项目类型
    project_type = 'org'
    # Base filters for this view
    # 此视图的基本过滤器
    base_filters = [['id', Project_Filter, project_type]]
    # Related views to display
    # 要显示的相关视图
    related_views = [
        Project_User_ModelView_Api,
    ]
    # Title for the view
    # 视图的标题
    label_title = '项目分组'
    # Extra fields for the edit form
    # 编辑表单的额外字段
    edit_form_extra_fields = {
        'type': StringField(
            _(datamodel.obj.lab('type')),
            description='项目分组',
            widget=MyBS3TextFieldWidget(value=project_type, readonly=1),
            default=project_type,
        ),
        'expand': StringField(
            _(datamodel.obj.lab('expand')),
            description=(
                '扩展参数。示例参数：<br>"cluster": "dev"<br>"node_selector":'
                ' "org=public"<br>"volume_mount":'
                ' "kubeflow-user-workspace(pvc):/mnt/;/data/k8s/../group1(hostpath):'
                '/mnt1;4G(memory):/dev/shm"<br>"SERVICE_EXTERNAL_IP":"xx.xx.xx.xx"'
            ),
            widget=MyBS3TextAreaFieldWidget(),
            default=json.dumps({'cluster': 'dev'}, indent=4, ensure_ascii=False),
        ),
    }
    # Extra fields for the add form (same as edit_form_extra_fields)
    # 添加表单的额外字段（与edit_form_extra_fields相同）
    add_form_extra_fields = edit_form_extra_fields


# Add the Project_ModelView_org_Api to the appbuilder
# 将Project_ModelView_org_Api添加到appbuilder
appbuilder.add_api(Project_ModelView_org_Api)


# Commented out: Project_ModelView for train models
# 已注释：用于训练模型的Project_ModelView
# class Project_ModelView_train_model(Project_ModelView_Base,MyappModelView):
#     project_type = 'model'
#     base_filters = [["id", Project_Filter, project_type]]
#     datamodel = SQLAInterface(Project)
#     label_title = '模型分组'
#
#


# Project_ModelView_train_model_Api class, inheriting from base and MyappModelRestApi
# Project_ModelView_train_model_Api类，继承自基类和MyappModelRestApi
class Project_ModelView_train_model_Api(Project_ModelView_Base, MyappModelRestApi):
    # Route base for the API endpoint
    # API端点的路由基础
    route_base = '/project_modelview/model/api'
    # Data model interface for Project
    # Project的数据模型接口
    datamodel = SQLAInterface(Project)
    # Project type for this view
    # 此视图的项目类型
    project_type = 'model'
    # Title for the view
    # 视图的标题
    label_title = '模型分组'
    # Base filters for this view
    # 此视图的基本过滤器
    base_filters = [['id', Project_Filter, project_type]]
    # Related views to display
    # 要显示的相关视图
    related_views = [
        Project_User_ModelView_Api,
    ]
    # Extra fields for the edit form
    # 编辑表单的额外字段
    edit_form_extra_fields = {
        'type': StringField(
            _(datamodel.obj.lab('type')),
            description='模型分组',
            widget=MyBS3TextFieldWidget(value=project_type, readonly=1),
            default=project_type,
        )
    }
    # Extra fields for the add form (same as edit_form_extra_fields)
    # 添加表单的额外字段（与edit_form_extra_fields相同）
    add_form_extra_fields = edit_form_extra_fields


# Add the Project_ModelView_train_model_Api to the appbuilder
# 将Project_ModelView_train_model_Api添加到appbuilder
appbuilder.add_api(Project_ModelView_train_model_Api)


# Project_ModelView_Api class, inheriting from base and MyappModelRestApi
# Project_ModelView_Api类，继承自基类和MyappModelRestApi
class Project_ModelView_Api(Project_ModelView_Base, MyappModelRestApi):
    # Data model interface for Project
    # Project的数据模型接口
    datamodel = SQLAInterface(Project)
    # Route base for the API endpoint
    # API端点的路由基础
    route_base = '/project_modelview/api'
    # Related views to display
    # 要显示的相关视图
    related_views = [
        Project_User_ModelView_Api,
    ]


# Add the Project_ModelView_Api to the appbuilder
# 将Project_ModelView_Api添加到appbuilder
appbuilder.add_api(Project_ModelView_Api)